<template>
  <ul class="bw-com-node-attr-list">
    <template v-for="item in curNodeAttrList" :key="item.key">
      <li class="bw-com-node-attr-item">
        <div class="handred" @click="item.isExpand = !item.isExpand">
          <span class="handred-title"> {{ item.name }} </span>

          <div class="handred-extra">
            <Icon
              class="bw-close-icon"
              :icon="
                item.isExpand
                  ? 'ant-design:down-outlined'
                  : 'ant-design:left-outlined'
              "
            />
          </div>
        </div>

        <div :class="['content', item.isExpand && 'content-expand']">
          <div class="content-item">
            <span class="label"> 属性值类型: </span>
            <a-select
              class="input"
              v-bind="getAttrDataTypeOptions(item)"
              v-model:value="curNodeAttrDataTypes[item.key]"
              @change="
                onChangeAttrValueDataType(
                  item.key,
                  curNodeAttrDataTypes[item.key]
                )
              "
            />
          </div>

          <div class="content-item">
            <span class="label"> 属性值来源: </span>
            <a-select
              class="input"
              :options="bwNodeAttrFromTypeList"
              v-model:value="curNodeAttrValueFroms[item.key]"
              @change="
                onChangeAttrValueFrom(item.key, curNodeAttrValueFroms[item.key])
              "
            />
          </div>

          <div class="content-item node-attr-value">
            <span class="label"> 属性值配置: </span>
            <BwNodeAttrConstValue
              class="input"
              :attrInfo="item"
              :attrData="curNodeAttrData"
              :valueFrom="curNodeAttrValueFroms[item.key]"
              :valueDataType="curNodeAttrDataTypes[item.key]"
              @change="onChangeAttrValue"
            />
          </div>
        </div>
      </li>
    </template>
  </ul>
</template>

<script lang="ts">
import { useComDesignStoreWithOut } from '@/store'
import { ref, unref, computed, watch, defineComponent } from 'vue'

import { BwCurNodeAttrInfoModel } from './constValue/props'
import {
  getNodeComAttrs,
  BwCustomComPropDataTypeEnum as BwPropDataTypeEnum,
  BwCustomComNodeAttrFromTypeEnum as BwAttrFromTypeEnum,
  BwCustomComNodeAttrDataTypeEnum as BwAttrDataTypeEnum,
  type BwCustomComNodeAttrModel,
} from '@bitwit/base-com-render'

import BwNodeAttrConstValue from './constValue/index.vue'
export default defineComponent({
  name: 'BwBaseComAttrSet',
  components: { BwNodeAttrConstValue },
  setup() {
    const designStore = useComDesignStoreWithOut()

    const curNodeId = ref<string>('')
    const curNodeAttrList = ref<Array<BwCurNodeAttrInfoModel>>([])
    const curNodeAttrData = ref<Record<string, BwCustomComNodeAttrModel>>({})
    const curNodeAttrValueFroms = ref<Record<string, BwAttrFromTypeEnum>>({})
    const curNodeAttrDataTypes = ref<
      Record<string, BwAttrDataTypeEnum | undefined>
    >({})

    const bwNodeAttrFromTypeList = computed(() => {
      const list = [
        { value: BwAttrFromTypeEnum.constValue, label: '常量' },
        { value: BwAttrFromTypeEnum.comProps, label: '外放属性' },
        { value: BwAttrFromTypeEnum.comVar, label: '组件变量' },
        {
          value: BwAttrFromTypeEnum.JSExpression,
          label: 'js表达式',
        },
      ]
      return list
    })

    /** 修改属性值 */
    const onChangeAttrValue = (name: string, value: any) => {
      const valueFrom = unref(curNodeAttrValueFroms)[name]
      const valueDataType = unref(curNodeAttrDataTypes)[name]

      const cusComAttrs = unref(curNodeAttrData)

      cusComAttrs[name] = cusComAttrs[name] ?? {}
      cusComAttrs[name].valueFromType = valueFrom
      cusComAttrs[name].valueDataType = valueDataType ?? null
      switch (valueFrom) {
        case BwAttrFromTypeEnum.JSExpression: {
          cusComAttrs[name].jsExpParams = value.jsExpParams
          cusComAttrs[name].jsExpBodyLogic = value.jsExpBodyLogic
          break
        }
        case BwAttrFromTypeEnum.comProps: {
          cusComAttrs[name].comPropsName = value
          break
        }
        case BwAttrFromTypeEnum.comVar: {
          cusComAttrs[name].comVarName = value
          break
        }
        case BwAttrFromTypeEnum.constValue: {
          cusComAttrs[name].constValue = value
          break
        }
      }

      designStore.onChangeNodeEleAttrs(unref(curNodeId), cusComAttrs)
    }

    /** 修改属性值数据类型 */
    const onChangeAttrValueDataType = (
      name: string,
      value?: BwAttrDataTypeEnum
    ) => {
      const cusComAttrs = unref(curNodeAttrData)

      cusComAttrs[name] = cusComAttrs[name] ?? {}
      cusComAttrs[name].valueDataType = value ?? null
      designStore.onChangeNodeEleAttrs(unref(curNodeId), cusComAttrs)
    }

    /** 获取属性值类型选择组件配置 */
    const getAttrDataTypeOptions = (data: BwCurNodeAttrInfoModel) => {
      const curProps: Record<string, any> = {}
      const dataType = data.dataType
      if (Array.isArray(dataType) && dataType.length) {
        curProps.options = []
        dataType.forEach((item) => {
          switch (item) {
            case BwPropDataTypeEnum.array: {
              curProps.options.push({
                label: '数组',
                value: item,
              })
              break
            }
            case BwPropDataTypeEnum.boolean: {
              curProps.options.push({
                label: '布尔值',
                value: item,
              })
              break
            }
            case BwPropDataTypeEnum.number: {
              curProps.options.push({
                label: '数字',
                value: item,
              })
              break
            }
            case BwPropDataTypeEnum.object: {
              curProps.options.push({
                label: '对象',
                value: item,
              })
              break
            }
            case BwPropDataTypeEnum.string: {
              curProps.options.push({
                label: '字符串',
                value: item,
              })
              break
            }
          }
        })
      }

      return curProps
    }

    /** 修改属性值来源 */
    const onChangeAttrValueFrom = (name: string, value: BwAttrFromTypeEnum) => {
      const cusComAttrs = unref(curNodeAttrData)

      cusComAttrs[name] = cusComAttrs[name] ?? {}
      cusComAttrs[name].valueFromType = value
      designStore.onChangeNodeEleAttrs(unref(curNodeId), cusComAttrs)
    }

    const toAttrDataType = (type?: BwPropDataTypeEnum) => {
      switch (type) {
        case BwPropDataTypeEnum.array: {
          return BwAttrDataTypeEnum.array
        }
        case BwPropDataTypeEnum.boolean: {
          return BwAttrDataTypeEnum.boolean
        }
        case BwPropDataTypeEnum.number: {
          return BwAttrDataTypeEnum.number
        }
        case BwPropDataTypeEnum.object: {
          return BwAttrDataTypeEnum.object
        }
        case BwPropDataTypeEnum.string: {
          return BwAttrDataTypeEnum.string
        }
        default: {
          return undefined
        }
      }
    }

    /** 初始化节点属性偏配置 */
    const initNodeAttrsConfig = (
      comName: string,
      curAttrs: Record<string, BwCustomComNodeAttrModel>
    ) => {
      const list = getNodeComAttrs(comName)

      curNodeAttrList.value = []
      curNodeAttrDataTypes.value = {}
      curNodeAttrValueFroms.value = {}
      if (Array.isArray(list) && list.length) {
        list.forEach((item) => {
          const curAttrItem = curAttrs[item.key]

          curNodeAttrDataTypes.value[item.key] =
            curAttrItem?.valueDataType ??
            toAttrDataType(item.defaultValueDataType ?? undefined)
          curNodeAttrValueFroms.value[item.key] =
            curAttrItem?.valueFromType ?? BwAttrFromTypeEnum.constValue
          curNodeAttrList.value.push({
            isExpand: true,

            key: item.key,
            name: item.name,
            isModel: !!item.isModel,
            isRequire: !!item.isRequire,
            dataType: item.dataType,
            defaultValue: item.defaultValue,
            defaultValueDataType: item.defaultValueDataType,
            constValueSetCom: item.constValueSetCom,
            constValueSetComProps: item.constValueSetComProps,
            remark: item.remark,
          })
        })
      }
    }

    watch(
      () => designStore.selectNodeEle,
      (newVal) => {
        curNodeId.value = ''
        if (newVal) {
          const comName = newVal.comName
          const curAttrs = newVal.attrs ?? {}

          curNodeId.value = newVal.nodeId
          curNodeAttrData.value = curAttrs
          initNodeAttrsConfig(comName, curAttrs)
        }
      },
      { deep: true, immediate: true }
    )

    return {
      curNodeAttrData,
      curNodeAttrList,
      curNodeAttrDataTypes,
      curNodeAttrValueFroms,
      bwNodeAttrFromTypeList,

      onChangeAttrValue,
      onChangeAttrValueFrom,
      getAttrDataTypeOptions,
      onChangeAttrValueDataType,
    }
  },
})
</script>

<style lang="less" scoped>
.bw-com-node-attr-list {
  padding: 0 16px;
  width: calc(100% - 32px);
  height: calc(100% - 16px);

  .bw-com-node-attr-item {
    width: 100%;
    border-radius: 5px;
    margin-bottom: 8px;
    border: 1px solid #e8e8e8;

    .handred {
      height: 30px;
      padding: 0 8px;
      width: calc(100% - 16px);
      display: inline-flex;
      align-items: center;
      justify-content: space-between;

      .handred-title {
        flex: 1;
      }
    }

    .content {
      height: 0;
      padding: 0 8px;
      overflow: hidden;
      width: calc(100% - 16px);
    }

    .content-expand {
      height: auto;
      padding: 8px;
      border-top: 1px solid #e8e8e8;

      .content-item {
        width: 100%;
        display: flex;
        align-items: center;
        margin-bottom: 3px;
        justify-content: space-between;

        .label {
          width: 80px;
        }

        .input {
          flex: 1;
        }
      }

      .node-attr-value {
        align-items: flex-start;
        .label {
          line-height: 32px;
        }
      }
    }
  }
}
</style>
